﻿/*
 * 2021.03.27-Code rectification and function enhancement.
 *            Huawei Device Co., Ltd. <mobile@huawei.com>
 */

#include "../StdAfx.h"
#include "UISlider.h"

namespace DuiLib {
IMPLEMENT_DUICONTROL(CSliderUI)
CSliderUI::CSliderUI() : m_uButtonState(0), m_nStep(1), m_bSendMove(false), m_bCanScrollWheel(false), m_nForeImagePadding(0)
{
    const int size = 10;
    m_uTextStyle = DT_SINGLELINE | DT_CENTER;
    m_szThumb.cx = m_szThumb.cy = size;
}

CSliderUI::~CSliderUI()
{
}

LPCTSTR CSliderUI::GetClass() const
{
    return _T("SliderUI");
}

UINT CSliderUI::GetControlFlags() const
{
    if (IsEnabled()) {
        return UIFLAG_SETCURSOR;
    } else {
        return 0;
    }
}

LPVOID CSliderUI::GetInterface(LPCTSTR pstrName)
{
    if (_tcsicmp(pstrName, DUI_CTR_SLIDER) == 0) {
        return static_cast<CSliderUI *>(this);
    }
    return CProgressUI::GetInterface(pstrName);
}

void CSliderUI::SetEnabled(bool bEnable)
{
    CControlUI::SetEnabled(bEnable);
    if (!IsEnabled()) {
        m_uButtonState = 0;
    }
}

int CSliderUI::GetChangeStep()
{
    return m_nStep;
}

void CSliderUI::SetChangeStep(int step)
{
    m_nStep = step;
}

void CSliderUI::SetThumbSize(SIZE szXY)
{
    m_szThumb = szXY;
}

RECT CSliderUI::GetThumbRect() const
{
    if (m_pManager == nullptr) {
        return RECT();
    }

    RECT rc = m_rcItem;
    const float floatNumber = 1.0f;
    SIZE scaledSize = CResourceManager::GetInstance()->Scale(*m_pManager, m_szThumb);
    int scaledForeImagePadding = CResourceManager::GetInstance()->Scale(*m_pManager, m_nForeImagePadding);
    if (m_nForeImagePadding > 0) {
        if (m_bHorizontal) {
            rc.right = round(m_rcItem.left +
                (m_nValue - m_nMin) * (m_rcItem.right - m_rcItem.left - 2 * scaledForeImagePadding) * floatNumber / (m_nMax - m_nMin));
            if (m_bThumbOverlapWithForeColor) {
                if (rc.right - rc.left <= scaledSize.cx) {
                    rc.right = rc.left + scaledSize.cx;
                }
                rc.left = rc.right - scaledSize.cx;
            }
            else {
                rc.left = rc.right;
                rc.right = rc.left + scaledSize.cx;
            }
        } else {
            rc.bottom = round(m_rcItem.top +
                (m_rcItem.bottom - m_rcItem.top) * (m_nMax - m_nValue - 2 * scaledForeImagePadding) * floatNumber / (m_nMax - m_nMin));

            if (m_bThumbOverlapWithForeColor) {
                if (rc.bottom - rc.top <= scaledSize.cy) {
                    rc.bottom = rc.top + scaledSize.cy;
                }

                rc.top = rc.bottom - scaledSize.cy;
            }
            else {
                rc.top = rc.bottom;
                rc.bottom = rc.top + scaledSize.cy;
            }
        }
    } else {
        if (m_bHorizontal) {
            rc.right = round(m_rcItem.left +
                (m_nValue - m_nMin) * (m_rcItem.right - m_rcItem.left) * floatNumber / (m_nMax - m_nMin));
            if (m_bThumbOverlapWithForeColor) {
                if (rc.right - rc.left <= scaledSize.cx) {
                    rc.right = rc.left + scaledSize.cx;
                }
                rc.left = rc.right - scaledSize.cx;
            }
            else {
                rc.left = rc.right;
                rc.right = rc.left + scaledSize.cx;
            }
        } else {
            rc.bottom = round(m_rcItem.top +
                (m_rcItem.bottom - m_rcItem.top) * (m_nMax - m_nValue) * floatNumber / (m_nMax - m_nMin));

            if (m_bThumbOverlapWithForeColor) {
                if (rc.bottom - rc.top <= scaledSize.cy) {
                    rc.bottom = rc.top + scaledSize.cy;
                }

                rc.top = rc.bottom - scaledSize.cy;
            }
            else {
                rc.top = rc.bottom;
                rc.bottom = rc.top + scaledSize.cy;
            }
        }
    }
    

    return rc;
}

LPCTSTR CSliderUI::GetThumbImage() const
{
    return m_sThumbImage;
}

void CSliderUI::SetThumbImage(LPCTSTR pStrImage)
{
    m_sThumbImage = pStrImage;
    Invalidate();
}

LPCTSTR CSliderUI::GetThumbHotImage() const
{
    return m_sThumbHotImage;
}

void CSliderUI::SetThumbHotImage(LPCTSTR pStrImage)
{
    m_sThumbHotImage = pStrImage;
    Invalidate();
}

LPCTSTR CSliderUI::GetThumbPushedImage() const
{
    return m_sThumbPushedImage;
}

void CSliderUI::SetThumbPushedImage(LPCTSTR pStrImage)
{
    m_sThumbPushedImage = pStrImage;
    Invalidate();
}

void CSliderUI::SetThumbOverlapWithForeColor(bool overlap)
{
    m_bThumbOverlapWithForeColor = overlap;
}

bool CSliderUI::SetThumbOverlapWithForeColor()
{
    return m_bThumbOverlapWithForeColor;
}

void CSliderUI::SetValue(int nValue)
{
    if ((m_uButtonState & UISTATE_CAPTURED) != 0) {
        return;
    }
    CProgressUI::SetValue(nValue);
}

bool CSliderUI::RefreshValue(const POINT& mouse, int mouseType)
{
    if (m_pManager == nullptr) {
        return false;
    }

    int nValue;
    const float multiples = 2.0f;
    SIZE scaledThumb = CResourceManager::GetInstance()->Scale(*m_pManager, m_szThumb);

    if (m_bHorizontal) {
        if (UICulture::GetInstance()->getDirection() == DIRECTION_RTL) {
            if (mouse.x >= m_rcItem.right - scaledThumb.cx) {
                nValue = m_nMin;
            }
            else if (mouse.x <= m_rcItem.left + scaledThumb.cx) {
                nValue = m_nMax;
            }
            else {
                nValue = round(m_nMax - (m_nMax - m_nMin) * (mouse.x - m_rcItem.left - scaledThumb.cx /
                    multiples) / (m_rcItem.right - m_rcItem.left - scaledThumb.cx));
            }
        } else {
            if (mouse.x >= m_rcItem.right - scaledThumb.cx) {
                nValue = m_nMax; 
            }
            else if (mouse.x <= m_rcItem.left + scaledThumb.cx) {
                nValue = m_nMin;
            }
            else {
                nValue = round(m_nMin + (m_nMax - m_nMin) * (mouse.x - m_rcItem.left - scaledThumb.cx /
                    multiples) / (m_rcItem.right - m_rcItem.left - scaledThumb.cx));
            }
        }
    } else {
        if (mouse.y >= m_rcItem.bottom - scaledThumb.cy) {
            nValue = m_nMin;
        } else if (mouse.y <= m_rcItem.top + scaledThumb.cy) {
            nValue = m_nMax;
        } else {
            nValue = round(m_nMin + (m_nMax - m_nMin) * (m_rcItem.bottom - mouse.y - scaledThumb.cy /
                multiples) / (m_rcItem.bottom - m_rcItem.top - scaledThumb.cy));
        }
    }
    if (m_nValue != nValue && nValue >= m_nMin && nValue <= m_nMax) {
        m_nValue = nValue;
        if (mouseType == UIEVENT_MOUSEMOVE && m_bSendMove) {
            m_pManager->SendNotify(this, DUI_MSGTYPE_VALUECHANGED);
        } else {
            m_pManager->SendNotify(this, DUI_MSGTYPE_VALUECHANGED);
        }
    }

    Invalidate();
    UpdateText();
}

void CSliderUI::DoEvent(TEventUI& event)
{
    if (!IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND) {
        if (m_pParent != nullptr) {
            m_pParent->DoEvent(event);
        } else {
            CLabelUI::DoEvent(event);
        }
    }

    if (event.Type == UIEVENT_BUTTONDOWN || event.Type == UIEVENT_DBLCLICK) {
        if (IsEnabled()) {
            m_uButtonState |= UISTATE_CAPTURED;

            RefreshValue(event.ptMouse, event.Type);
        }
    }
    if (event.Type == UIEVENT_BUTTONUP || event.Type == UIEVENT_RBUTTONUP) {
        if (IsEnabled()) {
            if ((m_uButtonState & UISTATE_CAPTURED) != 0) {
                m_uButtonState &= ~UISTATE_CAPTURED;
            }

            RefreshValue(event.ptMouse, event.Type);
        }
    }
    if (event.Type == UIEVENT_CONTEXTMENU) {
        return;
    }
    if (event.Type == UIEVENT_SCROLLWHEEL) {
        if (IsEnabled() && m_bCanScrollWheel) {
            if (m_pManager == nullptr) {
                return;
            }
            switch (LOWORD(event.wParam)) {
                case SB_LINEUP:
                    SetValue(GetValue() + GetChangeStep());
                    m_pManager->SendNotify(this, DUI_MSGTYPE_VALUECHANGED);
                case SB_LINEDOWN:
                    SetValue(GetValue() - GetChangeStep());
                    m_pManager->SendNotify(this, DUI_MSGTYPE_VALUECHANGED);
            }
        }
    }
    if (event.Type == UIEVENT_MOUSEMOVE) {
        if ((m_uButtonState & UISTATE_CAPTURED) != 0) {
            RefreshValue(event.ptMouse, event.Type);
        }

        POINT pt = event.ptMouse;
        RECT rcThumb = GetThumbRect();
        if (IsEnabled() && ::PtInRect(&rcThumb, pt)) {
            m_uButtonState |= UISTATE_HOT;
            Invalidate();
        } else {
            m_uButtonState &= ~UISTATE_HOT;
            Invalidate();
        }
    }
    if (event.Type == UIEVENT_SETCURSOR) {
        RECT rcThumb = GetThumbRect();
        if (IsEnabled()) {
            ::SetCursor(::LoadCursor(nullptr, MAKEINTRESOURCE(IDC_HAND)));
        }
    }

    if (event.Type == UIEVENT_MOUSELEAVE) {
        if (IsEnabled()) {
            m_uButtonState &= ~UISTATE_CAPTURED;
            m_uButtonState &= ~UISTATE_HOT;
            Invalidate();
        }
    }
    CLabelUI::DoEvent(event);
}

void CSliderUI::SetCanSendMove(bool bCanSend)
{
    m_bSendMove = bCanSend;
}
bool CSliderUI::GetCanSendMove() const
{
    return m_bSendMove;
}

void CSliderUI::SetCanScroolWheel(bool canScrollWheel)
{
    m_bCanScrollWheel = canScrollWheel;
}

void CSliderUI::SetForeImagePadding(int nValue)
{
    m_nForeImagePadding = nValue;
}

bool CSliderUI::GetCanScroolWheel() const
{
    return m_bCanScrollWheel;
}

void CSliderUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
{
    const int radix = 10;
    if (_tcsicmp(pstrName, _T("thumbimage")) == 0) {
        SetThumbImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("thumbhotimage")) == 0) {
        SetThumbHotImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("thumbpushedimage")) == 0) {
        SetThumbPushedImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("thumbsize")) == 0) {
        SIZE szXY = { 0 };
        LPTSTR pstr = nullptr;
        szXY.cx = _tcstol(pstrValue, &pstr, radix);
        ASSERT(pstr);
        szXY.cy = _tcstol(pstr + 1, &pstr, radix);
        ASSERT(pstr);
        SetThumbSize(szXY);
    } else if (_tcsicmp(pstrName, _T("step")) == 0) {
        SetChangeStep(_ttoi(pstrValue));
    } else if (_tcsicmp(pstrName, _T("sendmove")) == 0) {
        SetCanSendMove(_tcsicmp(pstrValue, _T("true")) == 0);
    } else if (_tcsicmp(pstrName, _T("thumboverlapwithforecolor")) == 0) {
        SetThumbOverlapWithForeColor(_tcsicmp(pstrValue, _T("true")) == 0);
    } else if (_tcsicmp(pstrName, _T("canscrollwheel")) == 0) {
        SetCanScroolWheel(_tcsicmp(pstrValue, _T("true")) == 0);
    } else if (_tcsicmp(pstrName, _T("foreimagepadding")) == 0) {
        SetForeImagePadding(_ttoi(pstrValue));
    } else {
        CProgressUI::SetAttribute(pstrName, pstrValue);
    }
}

void CSliderUI::PaintImage(HDC hDC, bool overlapWithForeColor)
{
    RECT rcThumb = GetThumbRect();
    rcThumb.left -= m_rcItem.left;
    rcThumb.top -= m_rcItem.top;
    rcThumb.right -= m_rcItem.left;
    rcThumb.bottom -= m_rcItem.top;

    if (m_pManager == nullptr) {
        return;
    }
    rcThumb.left = CResourceManager::GetInstance()->RestoreScale(*m_pManager, rcThumb.left);
    rcThumb.top = CResourceManager::GetInstance()->RestoreScale(*m_pManager, rcThumb.top);
    rcThumb.right = CResourceManager::GetInstance()->RestoreScale(*m_pManager, rcThumb.right);
    rcThumb.bottom = CResourceManager::GetInstance()->RestoreScale(*m_pManager, rcThumb.bottom);

    CDuiString image;

    if (overlapWithForeColor) {
        image = m_sForeImage;
    } else {
        image = m_sThumbImage;
        if ((m_uButtonState & UISTATE_CAPTURED) != 0) {
            if (!m_sThumbPushedImage.IsEmpty()) {
                m_sImageModify.Empty();
                m_sImageModify.SmallFormat(_T("dest='%d,%d,%d,%d'"), rcThumb.left, rcThumb.top, rcThumb.right,
                    rcThumb.bottom);
                if (!DrawImage(hDC, (LPCTSTR)m_sThumbPushedImage, (LPCTSTR)m_sImageModify)) {
                } else {
                    return;
                }
            }
        } else if ((m_uButtonState & UISTATE_HOT) != 0) {
            if (!m_sThumbHotImage.IsEmpty()) {
                m_sImageModify.Empty();
                m_sImageModify.SmallFormat(_T("dest='%d,%d,%d,%d'"), rcThumb.left, rcThumb.top, rcThumb.right,
                    rcThumb.bottom);
                if (!DrawImage(hDC, (LPCTSTR)m_sThumbHotImage, (LPCTSTR)m_sImageModify)) {
                } else {
                    return;
                }
            }
        }
    }


    if (!image.IsEmpty()) {
        m_sImageModify.Empty();
        m_sImageModify.SmallFormat(_T("dest='%d,%d,%d,%d'"), rcThumb.left, rcThumb.top, rcThumb.right, rcThumb.bottom);

        if (!DrawImage(hDC, (LPCTSTR)image, (LPCTSTR)m_sImageModify)) {
        } else {
            return;
        }
    }
}

void CSliderUI::PaintStatusImage(HDC hDC)
{
}

void CSliderUI::PaintForeImage(HDC hDC)
{
    if (m_bThumbOverlapWithForeColor) {
        PaintImage(hDC, true);
    } else {
        if (m_nForeImagePadding > 0) {
            if (m_pManager == nullptr) {
                return;
            }

            if (m_nMax <= m_nMin) {
                m_nMax = m_nMin + 1;
            }
            if (m_nValue > m_nMax) {
                m_nValue = m_nMax;
            }
            if (m_nValue < m_nMin) {
                m_nValue = m_nMin;
            }

            RECT rc = { 0 };
            if (m_bHorizontal) {
                rc.right = (m_nValue - m_nMin) * (m_rcItem.right - m_rcItem.left - 2 * m_nForeImagePadding) / (m_nMax - m_nMin) + m_nForeImagePadding;
                rc.bottom = m_rcItem.bottom - m_rcItem.top;
            }  else {
                rc.top = (m_rcItem.bottom - m_rcItem.top) * (m_nMax - m_nValue) / (m_nMax - m_nMin);
                rc.right = m_rcItem.right - m_rcItem.left;
                rc.bottom = m_rcItem.bottom - m_rcItem.top;
            }

            if (m_sForeImage.IsEmpty()) {
                return;
            }
            m_sForeImageModify.Empty();
            constexpr int offset = 2;
            constexpr int multiplyToStart = 2;
            if (m_bStretchForeImage) {
                m_sForeImageModify.SmallFormat(_T("dest='%d,%d,%d,%d'"),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.left + m_nForeImagePadding), DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.top),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.right), DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.bottom));
            }
            else if (m_cornerRadius == 0 ||
                rc.right <= multiplyToStart * DPI_SCALE(m_cornerRadius) || !m_bHorizontal) {
                m_sForeImageModify.SmallFormat(_T("dest='%d,%d,%d,%d' source='%d,%d,%d,%d'"),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.left + m_nForeImagePadding), DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.top),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.right), DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.bottom),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.left), DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.top),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.right), DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.bottom));
            }
            else {
                // 当前只为水平进度条做了右端圆角
                RECT rightCornorSource = {
                    m_rcItem.right - m_rcItem.left - DPI_SCALE(m_cornerRadius + offset),
                    rc.top, m_rcItem.right - m_rcItem.left, rc.bottom
                };
                RECT rightCornorDest = { rc.right - DPI_SCALE(m_cornerRadius + offset), rc.top, rc.right, rc.bottom };

                m_cornorImageModify.Empty();
                m_cornorImageModify.SmallFormat(_T("dest='%d,%d,%d,%d' source='%d,%d,%d,%d'"),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rightCornorDest.left),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rightCornorDest.top),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rightCornorDest.right),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rightCornorDest.bottom),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rightCornorSource.left),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rightCornorSource.top),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rightCornorSource.right),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rightCornorSource.bottom));
                DrawImage(hDC, (LPCTSTR)m_sForeImage, (LPCTSTR)m_cornorImageModify);

                rc.right -= DPI_SCALE(m_cornerRadius + offset);
                m_sForeImageModify.SmallFormat(_T("dest='%d,%d,%d,%d' source='%d,%d,%d,%d'"),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.left), DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.top),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.right), DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.bottom),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.left), DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.top),
                    DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.right), DPI_UNSCALE_PAINTMANAGER(*m_pManager, rc.bottom));
            }

            DrawImage(hDC, (LPCTSTR)m_sForeImage, (LPCTSTR)m_sForeImageModify);
        } else {
            CProgressUI::PaintForeImage(hDC);
        }
        PaintImage(hDC);
    }
}
void CSliderUI::PaintForeColor(HDC hDC)
{
    if (m_dwForeColor == 0)
        return;

    if (m_nMax <= m_nMin) {
        m_nMax = m_nMin + 1;
    }
    if (m_nValue > m_nMax) {
        m_nValue = m_nMax;
    }
    if (m_nValue < m_nMin) {
        m_nValue = m_nMin;
    }

    RECT rc = m_rcItem;
    const float floatNumber = 1.0f;
    if (m_bHorizontal) {
        rc.right = round(m_rcItem.left +
            (m_nValue - m_nMin) * (m_rcItem.right - m_rcItem.left) * floatNumber / (m_nMax - m_nMin));

        if (m_bThumbOverlapWithForeColor) {
            SIZE scaledSize = CResourceManager::GetInstance()->Scale(*m_pManager, m_szThumb);
            if (rc.right - rc.left <= scaledSize.cx) {
                rc.right = rc.left + scaledSize.cx;
            }
        }
    } else {
        rc.bottom = round(m_rcItem.top +
            (m_rcItem.bottom - m_rcItem.top) * (m_nMax - m_nValue) * floatNumber / (m_nMax - m_nMin));

        if (m_bThumbOverlapWithForeColor) {
            SIZE scaledSize = CResourceManager::GetInstance()->Scale(*m_pManager, m_szThumb);
            if (rc.bottom - rc.top <= scaledSize.cy) {
                rc.bottom = rc.top + scaledSize.cy;
            }
        }
    }

    int round = CResourceManager::GetInstance()->Scale(*m_pManager, m_bkRound);

    CRenderEngine::DrawColor(hDC, rc, GetAdjustColor(m_dwForeColor), round, true);
}
}
